package com.fmboy.MXH.nav.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fmboy.MXH.nav.domain.dto.PasswordResetDTO;
import com.fmboy.MXH.nav.domain.dto.UserDTO;
import com.fmboy.MXH.nav.domain.entities.User;
import com.fmboy.MXH.nav.domain.pojo.UserVO;
import com.fmboy.MXH.nav.mapper.UserMapper;
import com.fmboy.MXH.nav.service.UserService;
import com.fmboy.MXH.nav.utils.UserContext;
import jakarta.annotation.Resource;
import jakarta.validation.ValidationException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserMapper userMapper;

    public void register(UserDTO userDTO) throws ValidationException {

        validateEmail(userDTO.getEmail());
        validatePassword(userDTO.getPassword(), userDTO.getConfirm_password());
        validateUsername(userDTO.getUsername()); // 验证用户名
        validateCaptcha(userDTO.getEmail(), userDTO.getVerification_code()); // 验证验证码
        //删除验证码
        EmailService.deleteCaptcha(userDTO.getEmail());

//        校验用户名是否存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userDTO.getUsername());
        User one = this.getOne(queryWrapper); // 获取单个结果
        if (one != null) {
            throw new ValidationException("注册失败，用户名已存在！");
        }

//        校验邮箱是否存在
        LambdaQueryWrapper<User> queryWrapperEmailQueryWrapper = new LambdaQueryWrapper<>();
        queryWrapperEmailQueryWrapper.eq(User::getEmail, userDTO.getEmail());
        User emailOne = this.getOne(queryWrapperEmailQueryWrapper);
        if (emailOne != null) {
            throw new ValidationException("注册失败，该邮箱已注册！");
        }
        User user = new User();
        BeanUtils.copyProperties(userDTO, user);
        user.setUpdateTime(LocalDateTime.now());
        user.setCreateTime(LocalDateTime.now());
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        this.save(user);
    }

    private void validateEmail(String email) throws ValidationException {
        if (email == null || !Pattern.matches("^(\\w+([-.][A-Za-z0-9]+)*){3,18}@\\w+([-.][A-Za-z0-9]+)*\\.\\w+([-.][A-Za-z0-9]+)*$", email)) {
            throw new ValidationException("失败, 邮箱格式不正确");
        }
    }

    private void validatePassword(String password, String confirmPassword) throws ValidationException {
        if (password == null || !password.matches("^(?=.*[a-zA-Z0-9._@!]).{5,32}$")) {
            throw new ValidationException("失败, 密码格式不正确");
        }
        if (!password.equals(confirmPassword)) {
            throw new ValidationException("失败, 两次输入密码不一致");
        }
    }

    private void validateCaptcha(String email, String captcha) throws ValidationException {
        if (!EmailService.verifyCaptcha(email, captcha)) {
            throw new ValidationException("验证码错误!");
        }
    }

    private void validateUsername(String username) throws ValidationException {
        if (username == null || !username.matches("^(?!\\d)[a-zA-Z0-9_]{5,16}$")) {
            throw new ValidationException("失败，用户名不符合规定！");
        }
    }

    private void validateEmailCode(String email, String verificationCode) throws ValidationException {
        if (!EmailService.verifyCaptcha(email, verificationCode)) {
            throw new ValidationException("验证码错误！");
        }
    }

    @Override
    public UserVO login(UserDTO userDTO) {
        if (userDTO.getUsername() == null || userDTO.getUsername().isEmpty()) {
            throw new ValidationException("登录失败, 用户名为空！");
        }
        if (userDTO.getPassword() == null || userDTO.getPassword().isEmpty()) {
            throw new ValidationException("登录失败, 密码为空！");
        }

        User user = new User();
        BeanUtils.copyProperties(userDTO, user);
        // 查询用户名和密码 密码是加密
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userDTO.getUsername())
                .eq(User::getPassword, user.getPassword());

        User one = this.getOne(queryWrapper);
        if (one == null) {
            throw new ValidationException("登录失败, 用户名或密码错误！");
        } else if (!one.getPassword().equals(user.getPassword())) {
            throw new ValidationException("登录失败, 用户名或密码错误！");
        }
        one.setPassword(null);
        UserVO userVO = new UserVO();
        BeanUtil.copyProperties(one, userVO);
        userVO.setCreate_time(one.getCreateTime());
        userVO.setUpdate_time(one.getUpdateTime());
        return userVO;
    }

    @Override
    public void PasswordReset(PasswordResetDTO passwordResetDTO) {
        // 验证验证码
        validateEmailCode(passwordResetDTO.getEmail(), passwordResetDTO.getVerification_code());
        //删除验证码
        EmailService.deleteCaptcha(passwordResetDTO.getEmail());
        //该邮箱未注册
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, passwordResetDTO.getEmail());
        User one = this.getOne(queryWrapper);
        if (one == null) {
            throw new ValidationException("重置密码失败，该邮箱未注册！");
        }
        //修改密码成功
        one.setPassword(DigestUtils.md5DigestAsHex(passwordResetDTO.getNew_password().getBytes()));
//        this.update().eq("id", one.getId()).update(one);
        this.updateById(one);
    }


    @Override
    public void updateByIdName(User user, String verificationCode) {
        validateCaptcha(user.getEmail(), verificationCode);
        //删除验证码
        EmailService.deleteCaptcha(user.getEmail());
        validateUsername(user.getUsername());
        //修改失败，用户名已存在！
        if (this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername())) != null) {
            throw new ValidationException("修改失败，用户名已存在！");
        }

//        this.update().eq("id", user.getId()).update(user);
        this.updateById(user);
    }

    @Override
    public void updateEmail(User user, String verificationCode) {
        //校验验证码
        validateEmailCode(user.getEmail(), verificationCode);
        //删除验证码
        EmailService.deleteCaptcha(user.getEmail());
        // 查询用户名和密码 密码是加密
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        // 校验密码
        User userFromDb = this.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, user.getId())
                .eq(User::getPassword, user.getPassword()));
        if (userFromDb == null) {
            throw new ValidationException("修改失败，密码错误！");
        }

        //验证传入的邮箱是否存在数据库中
        if (this.getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, user.getEmail())) != null) {
            throw new ValidationException("修改失败，此邮箱已被绑定！");
        }

//        this.update().eq("id", user.getId()).update(user);
        this.updateById(user);
    }

    @Override
    public void updatePassword(UserDTO userDto) {
        // 获取当前用户id
        userDto.setId(Math.toIntExact(UserContext.getUserId()));

        // 两次输入密码不一致
        if (!Objects.equals(userDto.getNew_password(), userDto.getConfirm_password())) {
            throw new ValidationException("两次输入密码不一致！");
        }
        // 新密码与旧密码不能相同
        if (Objects.equals(userDto.getPassword(), userDto.getConfirm_password())) {
            throw new ValidationException("新密码与确认密码不能相同！");
        }
        // 查询用户名和密码 密码是加密
        userDto.setPassword(DigestUtils.md5DigestAsHex(userDto.getPassword().getBytes()));
        // 校验密码
        User userFromDb = this.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, userDto.getId())
                .eq(User::getPassword, userDto.getPassword()));
        if (userFromDb == null) {
            throw new ValidationException("修改失败，密码错误！");
        }
        User user = new User();
        BeanUtil.copyProperties(userDto, user);
        user.setPassword(DigestUtils.md5DigestAsHex(userDto.getNew_password().getBytes()));
        this.updateById(user);
    }

    @Override
    public void updateAvatar(String fileUrl) {
        try {
            User user = new User();
            user.setId(Math.toIntExact(UserContext.getUserId()));
            user.setAvatar(fileUrl);
            this.updateById(user);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public List<UserVO> getAllUser(String username, String email) {
        try {
            // 动态构建查询条件
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(StringUtils.hasText(username), User::getUsername, username)
                    .eq(StringUtils.hasText(email), User::getEmail, email);

            // 执行查询（无论是否有条件都会正确处理）
            List<User> users = userMapper.selectList(queryWrapper);

            // 转换为VO列表
            return convertToUserVOList(users);
        } catch (Exception e) {
            throw new ValidationException("获取用户失败: " + e.getMessage(), e);
        }
    }

    @Override
    public UserVO getUserInfo(Integer id) {
        try {
            User user = userMapper.selectById(id);
            if (user == null) {
                throw new ValidationException("用户不存在");
            }

            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            userVO.setCreate_time(user.getCreateTime());
            userVO.setUpdate_time(user.getUpdateTime());

            return userVO;
        } catch (Exception e) {
            throw new ValidationException("获取用户失败: " + e.getMessage(), e);
        }
    }

    @Override
    public void addUser(UserDTO userDTO) {
        validatePassword(userDTO.getPassword(), userDTO.getConfirm_password()); // 验证密码
        validateUsername(userDTO.getUsername()); // 验证用户名
        validateEmail(userDTO.getEmail()); // 验证邮箱
        User one = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userDTO.getUsername()));
        if (one != null) {
            throw new ValidationException("用户名已存在！");
        }
        if (this.getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, userDTO.getEmail())) != null) {
            throw new ValidationException("邮箱已被注册！");
        }
        User user = new User();
        user.setUsername(userDTO.getUsername());
        user.setPassword(DigestUtils.md5DigestAsHex(userDTO.getPassword().getBytes()));
        user.setEmail(userDTO.getEmail());
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        this.save(user);
    }

    @Override
    public void AdminUpdateUserInfo(UserDTO userDTO) {
        try {
            validateEmail(userDTO.getEmail()); // 验证邮箱格式或规则

            User existingUser = this.getById(userDTO.getId());

            if (!existingUser.getEmail().equals(userDTO.getEmail())) { // 检查新邮箱是否不同于旧邮箱
                if (this.getOne(new LambdaQueryWrapper<User>().eq(User::getEmail, userDTO.getEmail())) != null) {
                    throw new ValidationException("邮箱已被注册！");
                }
            }

            User updatedUser = new User();
            BeanUtils.copyProperties(userDTO, updatedUser); // 从DTO复制属性到实体
            updatedUser.setUpdateTime(LocalDateTime.now());

            this.updateById(updatedUser);
        } catch (BeansException e) {
            throw new RuntimeException("属性复制时发生错误", e);
        }
    }

    @Override
    public void AdminUpdateUserPassword(UserDTO userDTO) {

        // 两次输入密码不一致
        if (!Objects.equals(userDTO.getNew_password(), userDTO.getConfirm_password())) {
            throw new ValidationException("两次输入密码不一致！");
        }
        User user = new User();
        BeanUtil.copyProperties(userDTO, user);
        user.setId(Math.toIntExact(userDTO.getId()));
        user.setPassword(DigestUtils.md5DigestAsHex(userDTO.getNew_password().getBytes()));
        this.updateById(user);
    }

    @Override
    public void AdminUpdateUserRole(UserDTO userDTO) {

        // 不能修改自己的信息
        if (Objects.equals(UserContext.getUserId().intValue(), userDTO.getId())) {
            throw new ValidationException("不能修改自己的信息");
        }

        // 角色校验：必须是 "admin" 或 "user"
        if (userDTO.getRole() == null || !Set.of("admin", "user").contains(userDTO.getRole())) {
            throw new ValidationException("角色只能是admin或者user");
        }

        // 创建并更新用户信息
        User user = new User();
        BeanUtil.copyProperties(userDTO, user);
        user.setUpdateTime(LocalDateTime.now());

        // 更新用户
        this.updateById(user);

    }

    @Override
    public void AdminUserById(Integer id) {
        if (id == null) {
            throw new ValidationException("删除失败,id不能为空");
        }
        if (id <= 0) {
            throw new ValidationException("删除失败,id不能小于等于0");
        }
        if (UserContext.getUserId().intValue() == id) {
            throw new ValidationException("删除失败,不能删除自己");
        }
        User byId = this.getById(id);
        if (byId == null) {
            throw new ValidationException("删除失败,此用户不存在");
        }

        this.removeById(id);
    }

    /**
     * 转换实体列表为VO列表
     */
    private List<UserVO> convertToUserVOList(List<User> users) {
        if (CollectionUtils.isEmpty(users)) {
            return Collections.emptyList();
        }

        return users.stream()
                .map(this::convertToUserVO)
                .collect(Collectors.toList());
    }

    /**
     * 单个实体转VO
     */
    private UserVO convertToUserVO(User user) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);

        // 处理特殊字段映射（推荐使用注解配置替代手动设置）
        vo.setCreate_time(user.getCreateTime());
        vo.setUpdate_time(user.getUpdateTime());
        return vo;
    }
}